package tech.yunland.shop.domain.service;

import com.moyuer.bsf.domain.dao.RoleDao;
import com.moyuer.bsf.domain.dao.UserDao;
import com.moyuer.bsf.domain.model.ConfigItem;
import com.moyuer.bsf.domain.model.HqlArgs;
import com.moyuer.bsf.domain.model.Organ;
import com.moyuer.bsf.domain.model.User;
import com.moyuer.bsf.domain.service.LogService;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.*;
import org.hibernate.sql.JoinType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.yunland.shop.domain.dao.*;
import tech.yunland.shop.domain.model.*;
import tech.yunland.shop.domain.until.ChangeSerizliableResult;

import java.math.BigDecimal;
import java.util.*;

/**
 * 销售单（收银）
 *
 * @author 王睿智 <geekrize@gmail.com>
 */

@Service
public class SaleBillService {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private static final String DELETE_ENTRIES_HQL = "delete from SaleBillEntry se where se.owner.id=?";

    private static final String DELETE_HANDLER_HQL = "delete from SaleBillHandler sh where sh.saleBillEntry.id=?";

    // private static final String DELETE_STORE_HQL = "delete from
    // StoreBillEntry sbe where sbe.owner.id=?";

    @Autowired
    private SaleBillDao saleBillDao;
    @Autowired
    private SaleBillEntryDao saleBillEntryDao;
    @Autowired
    private SaleBillHandlerDao saleBillHandlerDao;
    @Autowired
    private SNGenerator snGenerator;
    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private GoodsPaidDao goodsPaidDao;
    @Autowired
    private IncomeDao incomeDao;
    @Autowired
    private CommissionDao commissionDao;
    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private StoreBillService storeBillService;
    @Autowired
    private LogService logService;

    @Autowired
    private GoodsPaidService goodsPaidService;

    /**
     * 读取销售单头
     *
     * @param id
     * @return
     */
    public SaleBill get(String id) {
        return saleBillDao.get(id);
    }

    /**
     * 新增销售单分录
     *
     * @param entries
     * @param owner
     * @param creator
     */
    private void addBillEntry(Set<SaleBillEntry> entries, SaleBill owner, User creator) {
        for (SaleBillEntry entry : entries) {
            entry.setOwner(owner);
            entry.setCreator(creator); // 分录创建人可能不同于原单据创建人
            entry.setState(0);
            entry.setPayment(0);
            saleBillEntryDao.save(entry);

            // 保存经手人
            if (entry.getHandlers() == null || entry.getHandlers().size() == 0) {
                continue;
            }

            for (SaleBillHandler handler : entry.getHandlers()) {
                handler.setOwner(entry);
                handler.setHandler(userDao.get(handler.getHandlerId()));
                handler.setJob(roleDao.get(handler.getJobId()));
                saleBillHandlerDao.save(handler);
            }
        }
    }

    /**
     * 新增销售单及其分录, 单据及分录状态全为未结算
     *
     * @param bill
     */
    private void addBill(SaleBill bill) {
        // 生成流水号
        bill.setSn(snGenerator.gen("sale", bill.getOrganId()));
        bill.setState(0);
        if (bill.getMemberId() != null) {
            bill.setMember(userDao.get(bill.getMemberId()));
        }
        // 保存销售单
        saleBillDao.save(bill);

        // 保存分录
        this.addBillEntry(bill.getEntries(), bill, bill.getCreator());
    }

    /**
     * 挂单
     *
     * @param bill
     */
    public void saveNotPay(SaleBill bill) {
        // 查找是否有该会员的销售单, 如果有, 将传入单据明细并入原销售单
        // 如果没有, 才保存为新的销售单

        DetachedCriteria criteria = DetachedCriteria.forClass(SaleBill.class);
        criteria.add(Restrictions.eq("state", 0)); // 未结算销售单
        criteria.createCriteria("organ").add(Restrictions.idEq(bill.getOrganId()));
        if (bill.getMemberId() == null || bill.getMemberId().equals("")) {
            criteria.add(Restrictions.isNull("member"));
        } else {
            criteria.createCriteria("member").add(Restrictions.idEq(bill.getMemberId()));
        }

        List<SaleBill> billList = saleBillDao.findByCriteria(criteria);
        if (billList == null || billList.size() == 0) {
            this.addBill(bill);
            return;
        }

        SaleBill indbBill = billList.get(0);
        // 为已存在的单据增加分录
        this.addBillEntry(bill.getEntries(), indbBill, bill.getCreator());

        // 重新计算应收金额
        indbBill = saleBillDao.get(indbBill.getId());

        BigDecimal receivable = BigDecimal.ZERO;

        receivable = bill.getReceivable().add(indbBill.getReceivable());

        indbBill.setReceivable(receivable);
        indbBill.setReceived(BigDecimal.ZERO); // 挂单下已结算分录将被移走, 所以此处已收金额为 0
        bill.setSn(indbBill.getSn());
        saleBillDao.update(indbBill);

        saleBillDao.deleteRepeat();// 删除无分录信息的销售单头
    }

    /**
     * 立即结算
     *
     * @param bill
     */
    public void saveAndPay(String SettlementType, ConfigItem configItem, SaleBill bill) {

        this.addBill(bill);
        // 更改状态
        bill.setState(1);

        // 重算销售单分录价格
        BigDecimal receivable = BigDecimal.ZERO;// 商品价格合计
        BigDecimal newReceived = BigDecimal.ZERO;
        for (SaleBillEntry entry : bill.getEntries()) {
            Goods goods = goodsDao.get(entry.getGoods().getId());
            receivable = receivable.add(goods.getPrice().multiply(entry.getQuantity()));
        }
        BigDecimal received = bill.getReceived();// 实收价格

        BigDecimal rate = received.divide(receivable, 10, BigDecimal.ROUND_HALF_UP);// 折扣比

        BigDecimal price = BigDecimal.ZERO;// 商品实际单价

        GoodsPaid memberPrice = null;

        BigDecimal scoreAmount = BigDecimal.ZERO;
        for (SaleBillEntry entry : bill.getEntries()) {

            Goods goods = goodsDao.get(entry.getGoods().getId());
            if (bill.getPayment() == 10) { //扣卡
                memberPrice = goodsPaidDao.getMemberPrizeBySql(entry.getGoods().getId().toString(),
                        bill.getOrgan().getId().toString(), bill.getMember().getId().toString());
                if (memberPrice == null) {
                    throw new RuntimeException("该会员余额不足，无法完成支付！");
                }
                int quantityRate = memberPrice.getQuantity().compareTo(BigDecimal.ZERO);
                if (quantityRate == 0) {
                    throw new RuntimeException("该会员余额不足，无法完成支付！");
                }
                price = memberPrice.getAmount().divide(memberPrice.getQuantity(), 10, BigDecimal.ROUND_HALF_UP);
                //现金 微信 支付宝 银行卡
            } else if (bill.getPayment() == 20 || bill.getPayment() == 60 || bill.getPayment() == 70 || bill.getPayment() == 80) {
                price = goods.getPrice().multiply(rate);
                price = price.setScale(10, BigDecimal.ROUND_HALF_UP);
            } else if (bill.getPayment() == 40) { //代金券
                memberPrice = goodsPaidDao.getMemberPrizeBySql(Goods.DJQ_ID, bill.getOrgan().getId().toString(),
                        bill.getMember().getId().toString());
                if (memberPrice == null) {
                    throw new RuntimeException("该会员代金券不足，无法完成支付！");
                }
                int quantityRate = memberPrice.getQuantity().compareTo(BigDecimal.ZERO);
                if (quantityRate == 0) {
                    throw new RuntimeException("该会员代金券不足，无法完成支付！");
                }
                price = memberPrice.getAmount().divide(memberPrice.getQuantity(), 10, BigDecimal.ROUND_HALF_UP);
//                price = price.multiply(goods.getPrice()).multiply(rate);
                price = price.multiply(goods.getPrice());
                price = price.setScale(10, BigDecimal.ROUND_HALF_UP);
//                price = goods.getPrice();
            } else if (bill.getPayment() == 30) { //积分
                if (goods.getScore() == null) {
                    throw new RuntimeException(goods.getName() + "不支持积分结算");
                }
                scoreAmount = scoreAmount.add(goods.getScore().multiply(entry.getQuantity()));
                price = BigDecimal.ZERO;
            } else if (bill.getPayment() == 50) { //赊帐
                User member = bill.getMember();
                if (member == null) {
                    throw new RuntimeException("非会员不可赊帐");
                }
                price = BigDecimal.ZERO;
            }

            entry.setAmount(price.multiply(entry.getQuantity()));
            entry.setPrice(price);
            entry.setState(1);
            entry.setPayment(bill.getPayment());// 分录添加支付方式

            newReceived = newReceived.add(price.multiply(entry.getQuantity()));

        }
        if (bill.getPayment() == 40) {
            bill.setReceived(received);
        }
        else if(bill.getPayment() == 20 || bill.getPayment() == 60 || bill.getPayment() == 70 || bill.getPayment() == 80){
            bill.setReceived(received);
        }
        else {
            bill.setReceived(newReceived);
        }

        if (bill.getPayment() == 50) {//如果为赊帐 标注该销售单为赊帐 state=-2 (0:挂单 1:已结算 -1:删除)
            bill.setState(Integer.valueOf(-2));
        }

        saleBillDao.update(bill);

        if (bill.getOldSaleBillId() != null) {

        }

		/* 1.预购信息 */
        BigDecimal memberBalanceAmount = BigDecimal.ZERO;//（结帐前的价值余额）

        if (bill.getMember() != null) {
            Map memberBalance = goodsPaidService.getMemberBalance(bill.getOrganId(), bill.getMemberId());
            if (memberBalance != null) {
                Object amount = memberBalance.get("real_price");
                memberBalanceAmount = amount == null ? BigDecimal.ZERO : (BigDecimal) amount;
            }
        }


        for (SaleBillEntry entry : bill.getEntries()) {
            // 会员消费
            if (bill.getMember() != null) {
                goodsPaidDao.substract(bill.getPayment(), bill.getOrgan().getId(), bill.getMember().getId(),
                        entry.getGoods().getId(), entry.getQuantity(), bill.getReceived(), bill, entry);
            } else {
                // TODO 非会员消费
            }
        }

        //设置会员余额
        if (bill.getMember() != null) {
            if (bill.getPayment().intValue() == 40) {//代金券
//                bill.setMemberBalance(memberBalanceAmount.subtract(received));
                bill.setMemberBalance(memberBalanceAmount.subtract(receivable));
            } else if (bill.getPayment().intValue() == 10) {//扣卡
                bill.setMemberBalance(memberBalanceAmount.subtract(receivable));
            } else if (bill.getPayment().intValue() == 20) {//现金
                bill.setMemberBalance(memberBalanceAmount);
            } else if (bill.getPayment().intValue() == 30) {//积分
                Goods goods = goodsDao.get(Goods.JF_ID);
                bill.setMemberBalance(memberBalanceAmount.subtract(scoreAmount.multiply(goods.getPrice())));
            } else if (bill.getPayment().intValue() == 50) { //赊帐
                bill.setMemberBalance(memberBalanceAmount);
            }
        }

        // 保存出库单及分录
        StoreBill storeBill = saleBillDao.saveStore(bill);
        storeBillService.saveStore(storeBill);
        logService.saveLog("出库单：[" + storeBill.getSn() + "]生成。", storeBill.getCreator());


        // 扣卡
        if (bill.getPayment() == 10) {
            incomeDao.addDeduction(bill.getOrgan().getId(), bill.getBizdate(), bill.getReceived());
            // 现金
        } else if (bill.getPayment() == 20 || bill.getPayment() == 60 || bill.getPayment() == 70 || bill.getPayment() == 80) {
            incomeDao.addCash(bill.getOrganId(), bill.getBizdate(), bill.getReceived());
            // TODO 积分
        } else if (bill.getPayment() == 30) {
            // 代金券
        } else if (bill.getPayment() == 40) {
            incomeDao.addDeduction(bill.getOrgan().getId(), bill.getBizdate(), newReceived);
        }

		/* 4.计算员工提成并计入报表(三种方式：不计算/按员工/按占比) 新增功能:区分立即结算与挂单结算 2016.11.07 */

        // 立即结算
        if (configItem != null) { //如果设置提成类型
            if (configItem.getValue().equals("user")) {
                // commissionDao.addSaleUser(bill);
                commissionDao.byUserSale(bill);
            } else if (configItem.getValue().equals("job")) {
                commissionDao.addSaleJob(bill);
            }
        }
    }


    /**
     * 挂单结算, 用于结算一个未结算销售单中的部分分录
     *  @param entriesId 分录标识集
     * @param creator   结算人
     * @param remark
     */
    public void payEntries(int payment, ConfigItem configItem, List<String> entriesId, String memberId, User creator,
                           BigDecimal receivable, BigDecimal received, String remark) {

        SaleBill bill = new SaleBill();
        bill.setCreator(creator);
        bill.setRemark(remark);

        String saleBillId = saleBillEntryDao.get(entriesId.get(0)).getOwner().getId();
        SaleBill saleBill = saleBillDao.get(saleBillId);
        User vip = saleBill.getMember();

        if (vip == null) {
            bill.setPayment(20);
        } else {
            User member = vip;
            bill.setMember(member);
            bill.setPayment(payment);
        }


        bill.setReceivable(receivable);
        bill.setReceived(received);

        Organ organ = new Organ();
        organ.setId(creator.getPrimaryOrganId());
        bill.setOrgan(organ);

        Set<SaleBillEntry> entries = new HashSet<SaleBillEntry>();

        SaleBill oldBill = null;

        for (String oldId : entriesId) {

            SaleBillEntry old = saleBillEntryDao.get(oldId);
            oldBill = old.getOwner();

            SaleBillEntry entry = new SaleBillEntry();

            entry.setOwner(bill);
            entry.setCreator(creator); // 分录创建人可能不同于原单据创建人
            entry.setGoods(old.getGoods());
            entry.setQuantity(old.getQuantity());
            entry.setAmount(old.getAmount());
            entry.setPayment(payment);

            Set<SaleBillHandler> handlers = new HashSet<SaleBillHandler>();
            List<SaleBillHandler> oldHandles = this.getHandle(old.getId());

            for (SaleBillHandler handler : oldHandles) {
                SaleBillHandler saleBillHandler = new SaleBillHandler();
                saleBillHandler.setOwner(entry);
                saleBillHandler.setHandler(handler.getHandler());
                saleBillHandler.setJob(handler.getJob());
                handlers.add(saleBillHandler);
                saleBillHandlerDao.delete(handler.getId()); // 删除原记录
            }
            entry.setHandlers(handlers);
            entries.add(entry);
            // 更新旧单应收
            oldBill.setReceivable(oldBill.getReceivable().subtract(old.getAmount()));
            saleBillDao.update(oldBill);

            saleBillEntryDao.deleteObject(old); // 删除原记录
        }

        if (oldBill != null && entriesId != null) {
            if (oldBill.getEntries() == null || oldBill.getEntries().size() == entriesId.size()) {
                saleBillDao.delete(oldBill.getId());
            }
        }
        bill.setEntries(entries);
        this.saveAndPay("shoppingCart", configItem, bill); // 立即结算新生成的单据
    }

    /**
     * 获取分录经手人
     *
     * @param salebillentryID
     * @return
     */
    private List<SaleBillHandler> getHandle(String salebillentryID) {
        DetachedCriteria criteriaHandle = DetachedCriteria.forClass(SaleBillHandler.class);
        criteriaHandle.createCriteria("owner").add(Restrictions.idEq(salebillentryID));
        List<SaleBillHandler> handleList = saleBillHandlerDao.findByCriteria(criteriaHandle);
        return handleList;
    }

    /**
     * 标记删除
     *
     * @param id
     */
    public void delete(String id) {
        SaleBill SaleBill = saleBillDao.get(id);
        if (SaleBill.getState() != -1) {
            SaleBill.setState(-1);
        } else {
            throw new RuntimeException("该活动已经删除");
        }
        saleBillDao.update(SaleBill);
    }

    /**
     * 根据条件生成 hql 查询
     *
     * @param param
     * @param states
     * @param goodsId
     * @param organIds
     * @return
     */
    private HqlArgs genHqlArgs(String param, List<Integer> states, String[] goodsId, List<String> organIds) {
        param = StringUtils.trimToEmpty(param);

        Map<String, Object> args = new HashMap<String, Object>();

        String hql = "from SaleBill s where 1=1  and s.entries.size > 0 AND EXISTS (SELECT e.id FROM s.entries e WHERE e.state <> -1) ";
        if (goodsId != null && goodsId.length > 0) {
            hql = "from SaleBillEntry se, SaleBill s where s.id=se.owner and se.goods.id in :goodsId and s.entries.size > 0 AND EXISTS (SELECT e.id FROM p.entries e WHERE e.state<>-1) ";
            args.put("goodsId", goodsId);
        }

        if (StringUtils.isNotBlank(param)) {
            if (param.contains("非")) {
                hql += " and (s.member.name like :arg or s.remark like :arg or s.sn like :arg or s.member.name like '% %')";
            } else {
                hql += " and (s.member.name like :arg or s.remark like :arg or s.sn like :arg or s.member.spell like :arg )";
                // hql += " and (s.remark like :arg or s.sn like :arg)";

            }
            args.put("arg", "%" + param + "%");
        }

        if (organIds != null && organIds.size() > 0) {
            if (organIds.size() == 1) {
                hql += " and s.organ.id = :organIds";
                args.put("organIds", organIds.get(0));
            } else {
                hql += " and s.organ.id in :organIds";
                args.put("organIds", organIds);
            }
        }

        if (states != null && states.size() > 0) {
            if (states.size() == 1) {
                hql += " and s.state=:states";
                args.put("states", states.get(0));
            } else {
                hql += " and s.state in :states";
                args.put("states", states);
            }
        } else {
            hql += " and s.state <> -1";
        }
        return new HqlArgs(hql, args);
    }

    /**
     * 根据入参查询结果数量
     *
     * @param param
     * @param states
     * @param goodsId
     * @param organIds
     * @return
     */
    public int getResultSize(String param, List<Integer> states, String[] goodsId, List<String> organIds) {
        HqlArgs hqlArgs = genHqlArgs(param, states, goodsId, organIds);
        return (int) saleBillDao.getCount(hqlArgs.getHql(), hqlArgs.getArgs());
    }

    /**
     * 根据入参查询结果集
     *
     * @param param    参数
     * @param states   状态
     * @param goodsId  商品ID
     * @param organIds 机构ID
     * @param length   数量
     * @return
     * @Return List<goods>
     */
    public List<SaleBill> getResultInfos(String param, List<Integer> states, String[] goodsId, Integer startIndex,
                                         Integer length, List<String> organIds) {
        HqlArgs hqlArgs = genHqlArgs(param, states, goodsId, organIds);
        String hql = "select s " + hqlArgs.getHql() + " order by s.state asc, s.createTime desc,s.sn desc";
        DetachedCriteria criteria = DetachedCriteria.forClass(SaleBill.class);
        criteria.createAlias("member", "user", JoinType.LEFT_OUTER_JOIN);
        List<String> pnames = new ArrayList();
        pnames.add("user.name");
        pnames.add("sn");
        pnames.add("user.spell");
        pnames.add("remark");

        criteria.addOrder(Order.asc("state"));
        criteria.addOrder(Order.desc("createTime"));
        this.getCond(criteria, param, states, organIds, pnames);
        return saleBillDao.findByCriteria(criteria, startIndex, length);


        // return saleBillDao.findByNamedParam(hql, startIndex, length, hqlArgs.getArgs());
    }

    /**
     * 李珂
     *
     * @param criteria     离线查询
     * @param param        查询参数
     * @param states       状态
     * @param organIds     可见机构
     * @param propertNames 属性列表
     */
    public void getCond(DetachedCriteria criteria, String param, List<Integer> states, List<String> organIds, List<String> propertNames) {
        List<Criterion> cs = new ArrayList<>();
        if (StringUtils.isNotBlank(param)) {//如果参数不为空
            for (String pname : propertNames
                    ) {

                if (pname.equals("user.name")) {


                    this.paseParamWithMember(pname, param, cs);
                } else {
                    this.paseParamOr(pname, param, cs);
                }
            }

        }
        if (cs.size() > 0) {
            Criterion[] cc = new Criterion[cs.size()];
            for (int i = 0; i < cs.size(); i++) {
                cc[i] = cs.get(i);
            }
            criteria.add(Restrictions.or(cc));
        }
        if (states != null && states.size() > 0) {
            criteria.add(Restrictions.in("state", states));
        }
        if (organIds != null && organIds.size() > 0) {
            criteria.createAlias("organ", "org", JoinType.LEFT_OUTER_JOIN)
                    .add(Restrictions.in("org.id", organIds));
        }
        criteria.add(Restrictions.ne("state", -1));
        criteria.add(Restrictions.sizeGt("entries",0));

    }

    private void paseParamWithMember(String pname, String param, List<Criterion> cs) {


        if (param.contains("非")
                || param.contains("会")
                || param.contains("员")) {
            cs.add(Restrictions.isNull(pname));
        } else {
            this.paseParamOr(pname, param, cs);
        }
    }

    public void paseParamOr(String pName, String param, List<Criterion> cs) {
        cs.add(Restrictions.like(pName, param, MatchMode.ANYWHERE).ignoreCase());

    }

    /**
     * 根据条件生成分录 hql 查询
     *
     * @param owner 上级表单ID
     * @return
     */
    private HqlArgs genEntryHqlArgs(String organId, String owner, List<Integer> states) {
        owner = StringUtils.trimToEmpty(owner);

        Map<String, Object> args = new HashMap<String, Object>();

        String hql = "from SaleBillEntry se where 1=1";
        if (StringUtils.isNotBlank(owner)) {
            hql += "and se.owner.id = :owner";
            args.put("owner", owner);
        }

        if (states != null && states.size() > 0) {
            if (states.size() == 1) {
                hql += " and se.state=:states";
                args.put("states", states.get(0));
            } else {
                hql += " and se.state in :states";
                args.put("states", states);
            }
        } else {
            hql += " and se.state <> -1";
        }

        if (organId != null) {
            hql += " and se.owner.organ.id=:organId";
            args.put("organId", organId);
        }

        return new HqlArgs(hql, args);
    }

    /**
     * 根据入参查询分录结果数量
     *
     * @param owner  上级表单ID
     * @param states 状态
     * @return
     */
    public int getEntryResultSize(String organId, String owner, List<Integer> states) {

        HqlArgs hqlArgs = genEntryHqlArgs(organId, owner, states);

        return saleBillEntryDao.findByNamedParam(hqlArgs.getHql(), hqlArgs.getArgs()).size();
    }

    /**
     * 根据入参查询分录结果集
     *
     * @param owner  上级表单ID
     * @param states 状态
     * @param length 数量
     * @return
     * @Return List<SaleBillEntry>
     */
    public List<SaleBillEntry> getEntryResultInfos(String organId, String owner, List<Integer> states,
                                                   Integer startIndex, Integer length) {
        HqlArgs hqlArgs = genEntryHqlArgs(organId, owner, states);
        String hql = "select se " + hqlArgs.getHql() + " order by se.createTime desc";
        return saleBillEntryDao.findByNamedParam(hql, startIndex, length, hqlArgs.getArgs());
    }

    /**
     * 根据条件生成销售经办人 hql 查询
     *
     * @param saleBillEntry 分录
     * @return
     */
    private HqlArgs genHandlerHqlArgs(String saleBillEntry) {
        saleBillEntry = StringUtils.trimToEmpty(saleBillEntry);
        Map<String, Object> args = new HashMap<String, Object>();
        String hql = "from SaleBillHandler sh where 1=1";
        if (StringUtils.isNotBlank(saleBillEntry)) {
            hql = "and sh.saleBillEntry.id = :saleBillEntry";
            args.put("saleBillEntry", saleBillEntry);
        }
        return new HqlArgs(hql, args);
    }

    /**
     * 根据入参查询销售经办人结果数量
     *
     * @param saleBillEntry 分录
     * @return
     */
    public int getHandlerResultSize(String saleBillEntry) {
        HqlArgs hqlArgs = genHandlerHqlArgs(saleBillEntry);
        return saleBillHandlerDao.findByNamedParam(hqlArgs.getHql(), hqlArgs.getArgs()).size();
    }

    /**
     * 根据入参查询销售经办人结果集
     *
     * @param saleBillEntry 分录
     * @param length        数量
     * @return List<SaleBillHandler>
     */
    public List<SaleBillHandler> getHandlerResultInfos(String saleBillEntry, Integer startIndex, Integer length) {
        HqlArgs hqlArgs = genHandlerHqlArgs(saleBillEntry);
        String hql = "select sh " + hqlArgs.getHql();
        return saleBillHandlerDao.findByNamedParam(hql, startIndex, length, hqlArgs.getArgs());
    }

    /**
     * 根据入参查询该组织下用户所有消费过的商品
     *
     * @param user
     * @param organ
     * @param state
     * @return
     */
    public HqlArgs genAllEntryHql(User user, Organ organ, Integer state) {
        Map<String, Object> args = new HashMap<String, Object>();
        String hql = " from SaleBill sb where 1=1 ";
        if (user != null) {
            hql += " and sb.member.id = :userId ";
            args.put("userId", user.getId());
        }
        if (organ != null) {
            hql += " and sb.organ.id = :organId ";
            args.put("organId", organ.getId());
        }
        if (state != null) {
            hql += " and sb.state = :state";
            args.put("state", state);
        }
        return new HqlArgs(hql, args);
    }

    /**
     * 根据入参查询结果数量
     *
     * @param user
     * @param organ
     * @param state
     * @return
     */
    public int getAllEntrySize(User user, Organ organ, Integer state) {
        HqlArgs hqlArgs = genAllEntryHql(user, organ, state);
        return saleBillDao.findByNamedParam(hqlArgs.getHql(), hqlArgs.getArgs()).size();
    }

    /**
     * 根据用户和组织查找该组织用户下所有消费记录
     *
     * @param user
     * @param organ
     * @param state
     * @return
     */
    public List<SaleBill> getAllEntryInfo(User user, Organ organ, Integer state, Integer startIndex, Integer length) {
        HqlArgs hqlArgs = genAllEntryHql(user, organ, state);
        String hql = "select sb " + hqlArgs.getHql() + " order by sb.bizdate desc";
        return saleBillDao.findByNamedParam(hql, startIndex, length, hqlArgs.getArgs());
    }

    /**
     * 根据 goodsId 获取 goodsUnit
     *
     * @param goodsId
     * @return
     */
    public Goods getGoodsUnit(String goodsId) {
        DetachedCriteria criteria = DetachedCriteria.forClass(Goods.class);
        criteria.add(Restrictions.idEq(goodsId));
        List<Goods> goods = goodsDao.findByCriteria(criteria);
        return goods.get(0);
    }

    public int getCount(String id) {
        String sql = "select count(1) as c from bill_sale_entry e,goods g\n" + "\n" + "where e.goods_id = g.id\n"
                + "  and\n" + "  owner_id = ?";

        Map<String, Object> cMap = saleBillDao.findUniqueBySQL(sql, new Object[]{id});
        Object c = cMap.get("c");
        if (c != null) {
            String count = c.toString();
            return Integer.parseInt(count);
        }
        return 0;
    }

    public List<HashMap<String, Object>> getByKey(String id, int startIdx, Integer rows) {
        String sql = "select e.amount amount,e.goods_id,e.id,g.name,e.quantity,g.price goodsPrice,e.create_time,e.payment,g.score ,ba.file_name as pictureName from bill_sale_entry e,goods g left join goods_pictures gp on gp.goods_id=g.id left join bsf_attachment ba on gp.picture_id=ba.id\n"
                + "\n" + "where e.goods_id = g.id\n" + "  and\n" + "  owner_id = ?";

        List<Map<String, Object>> list = saleBillDao.findBySQL(sql, startIdx, rows, new Object[]{id});
        List<HashMap<String, Object>> newlist = ChangeSerizliableResult.changeToSerizliable(list);
        return newlist;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    public List<SaleBill> getAllSaleBil() {
        String hql = "from SaleBill where state = ?";
        return saleBillDao.find(hql, 1);
    }

    public GoodsPaid getGoodsPaid(String goodsId, String organId, String memberId) {
        return goodsPaidDao.getMemberPrizeBySql(goodsId, organId, memberId);
    }

    /**
     * 还款
     *
     * @param billId
     */
    public void repayment(String billId) {
        SaleBill bill = saleBillDao.get(billId);
        if (bill != null && bill.getState().intValue() == -2) {
            bill.setState(1);
            saleBillDao.update(bill);
        }
    }

    /**
     * 查看分录详情
     *
     * @param id
     * @return
     */
    public SaleBillEntry getSaleBillEntry(String id) {
        return saleBillEntryDao.get(id);
    }
}
